Removing an old, cherished, yet pointless caveat "This documentation is
[supercollider.git] / Help / Extending and Customizing SC / Writing Primitives.html
blobc73119c08960775aa135f1cf176bd58b942a9b13
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <meta http-equiv="Content-Style-Type" content="text/css">
6 <title></title>
7 <meta name="Generator" content="Cocoa HTML Writer">
8 <meta name="CocoaVersion" content="824.42">
9 <style type="text/css">
10 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica}
11 p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; min-height: 12.0px}
12 p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
13 p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
14 p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #0000c1}
15 p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #216e23}
16 p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #780850; min-height: 12.0px}
17 p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #780850}
18 p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
19 p.p10 {margin: 0.0px 0.0px 0.0px 10.0px; font: 9.0px Monaco; color: #0000e1; min-height: 12.0px}
20 p.p11 {margin: 0.0px 0.0px 0.0px 10.0px; font: 12.0px Helvetica; color: #0000e1}
21 span.s1 {color: #0000c1}
22 span.s2 {color: #000000}
23 span.s3 {color: #780850}
24 span.s4 {color: #0000ff}
25 span.s5 {color: #8d0c11}
26 span.s6 {font: 9.0px Monaco}
27 span.s7 {color: #216e23}
28 span.s8 {font: 12.0px Helvetica}
29 span.Apple-tab-span {white-space:pre}
30 </style>
31 </head>
32 <body>
33 <p class="p1"><b>Writing Primitives</b></p>
34 <p class="p2"><br></p>
35 <p class="p3"><b>In SuperCollider code:</b></p>
36 <p class="p2"><br></p>
37 <p class="p4">Cocoa {</p>
38 <p class="p4"><span class="Apple-tab-span"> </span>prGetPathsDialog { <span class="s1">arg</span> returnSlot;</p>
39 <p class="p5"><span class="s2"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>_Cocoa_GetPathsDialog</p>
40 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>^<span class="s1">this</span>.primitiveFailed</p>
41 <p class="p4"><span class="Apple-tab-span"> </span>}</p>
42 <p class="p4">}</p>
43 <p class="p2"><br></p>
44 <p class="p3"><b>In your primitive source code define the primitive:</b></p>
45 <p class="p2"><br></p>
46 <p class="p4"><span class="Apple-tab-span"> </span><span class="s3">void</span> initCocoaFilePrimitives()</p>
47 <p class="p4"><span class="Apple-tab-span"> </span>{</p>
48 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s3">int</span> base, index;</p>
49 <p class="p2"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></p>
50 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>base = nextPrimitiveIndex();</p>
51 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>index = <span class="s4">0</span>;</p>
52 <p class="p2"><span class="Apple-tab-span"> </span></p>
53 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>definePrimitive(base, index++, <span class="s5">"_Cocoa_GetPathsDialog"</span>, prGetPathsDialog, <span class="s4">2</span>, <span class="s4">0</span>);<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>// further primitives can be laid in...</p>
54 <p class="p6"><span class="s2"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>//definePrimitive(base, index++, "_Cocoa_SaveAsPlist", prSaveAsPlist, 3, 0);</p>
55 <p class="p4"><span class="Apple-tab-span"> </span>}</p>
56 <p class="p2"><span class="Apple-tab-span"> </span></p>
57 <p class="p7"><br></p>
58 <p class="p8">Here is the prototype for definePrimitive:</p>
59 <p class="p7"><span class="Apple-tab-span"> </span></p>
60 <p class="p4"><span class="s3"><span class="Apple-tab-span"> </span>int</span> definePrimitive(<span class="s3">int</span> base, <span class="s3">int</span> index, <span class="s3">char</span> *name, PrimitiveHandler handler, <span class="s3">int</span> numArgs, <span class="s3">int</span> varArgs);</p>
61 <p class="p2"><br></p>
62 <p class="p3">The numArgs is the number of arguments that were passed into the SuperCollider method that calls the primitive, plus one to include the receiver which is passed in as the first argument. <span class="Apple-converted-space"> </span></p>
63 <p class="p2"><br></p>
64 <p class="p3">(TODO varArgs ...)</p>
65 <p class="p2"><span class="Apple-converted-space"> </span></p>
66 <p class="p3"><b>Write your primitive</b></p>
67 <p class="p2"><br></p>
68 <p class="p3"><span class="s6">g-&gt;sp </span>is the top of the stack and is the last argument pushed.<span class="Apple-converted-space"> </span></p>
69 <p class="p3"><span class="s6">g-&gt;sp - inNumArgsPushed + 1 </span>is the receiver and where the result goes.</p>
70 <p class="p2"><br></p>
71 <p class="p3">In this example, the numArgsPushed will be 2 (as specified in definePrimitive)</p>
72 <p class="p2"><br></p>
73 <p class="p4"><span class="Apple-tab-span"> </span><span class="s3">int</span> prGetPathsDialog(<span class="s3">struct</span> VMGlobals *g, <span class="s3">int</span> numArgsPushed);</p>
74 <p class="p4"><span class="Apple-tab-span"> </span><span class="s3">int</span> prGetPathsDialog(<span class="s3">struct</span> VMGlobals *g, <span class="s3">int</span> numArgsPushed)</p>
75 <p class="p4"><span class="Apple-tab-span"> </span>{</p>
76 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-converted-space">        </span><span class="s3">if</span> (!g-&gt;canCallOS) <span class="s3">return</span> errCantCallOS;<span class="s7">//if its deferred, does this matter ?</span></p>
77 <p class="p2"><span class="Apple-tab-span"> </span></p>
78 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-converted-space">        </span>PyrSlot *receiver = g-&gt;sp - <span class="s4">1</span>; <span class="s7">// an instance of Cocoa</span></p>
79 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-converted-space">        </span>PyrSlot *array = g-&gt;sp; <span class="s7">// an array</span></p>
80 <p class="p2"><span class="Apple-tab-span"> </span></p>
81 <p class="p4"><span class="Apple-tab-span"> </span>// ...<span class="Apple-converted-space">  </span>the body</p>
82 <p class="p2"><span class="Apple-tab-span"> </span></p>
83 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-converted-space">        </span><span class="s3">return</span> errNone;</p>
84 <p class="p4"><span class="Apple-tab-span"> </span>}</p>
85 <p class="p2"><span class="Apple-tab-span"> </span></p>
86 <p class="p3">This example does not set the receiver, so the primitive returns the original receiver unchanged (still an instance of Cocoa).</p>
87 <p class="p2"><br></p>
88 <p class="p3">or set the object at</p>
89 <p class="p2"><span class="Apple-tab-span"> </span></p>
90 <p class="p4"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>receiver</p>
91 <p class="p9"><br></p>
92 <p class="p4"><span class="s8">which again is at</span> (g-&gt;sp - numArgsPushed + 1)</p>
93 <p class="p10"><br></p>
94 <p class="p2"><br></p>
95 <p class="p3"><b>some guidelines:</b></p>
96 <p class="p9"><br></p>
97 <p class="p3">If possible, you should avoid creating objects in a primitive. Primitives are much simpler to write and debug if you pass in an object that you create in SC code and fill in its slots in the primitive.</p>
98 <p class="p9"><br></p>
99 <p class="p3">When you do fill in slots in an object with other objects, you must call g-&gt;gc-&gt;GCWrite(obj, slot) in order to notify the garbage collector that you have modified a slot that it may have already scanned.</p>
100 <p class="p9"><br></p>
101 <p class="p3">Do not store pointers to PyrObjects in C/C++ variables unless you can absolutely guarantee that they cannot be garbage collected. For example the File and SCWindow classes do this by storing the objects in an array in a classvar. The object has to stay in that array until no C object refers to it.</p>
102 <p class="p9"><br></p>
103 <p class="p3">Failing to observe the above two points can result in very hard to find bugs.</p>
104 <p class="p9"><br></p>
105 <p class="p3">If you create more than one object in a primitive you must make sure that all the previously created objects are reachable before you allocate another. In other words you must store them on the stack or in another object's slots before creating another. Creating objects can call the garbage collector and if you have not made your objects reachable, they can get collected out from under you.</p>
106 <p class="p9"><br></p>
107 <p class="p3">Since SC is dynamically typed, you cannot rely on any of the arguments being of the class you expect. You should check every argument to make sure it is the correct type. One way to do this is by using isKindOfSlot.<span class="Apple-converted-space">  </span>If you just want a numeric value, you can use slotIntVal, slotFloatVal, or slotDoubleVal which will return an error if the value is not a numeric type. Similarly there is slotStringVal.<span class="Apple-converted-space"> </span></p>
108 <p class="p3">It is safe to assume that the receiver will be of the correct type because this is ensured by the method dispatch mechanism.</p>
109 <p class="p9"><br></p>
110 <p class="p9"><br></p>
111 <p class="p11">Q: now where do i put the thing to return it ?</p>
112 <p class="p9"><br></p>
113 <p class="p3">A: into g-&gt;sp - inNumArgsPushed + 1.</p>
114 <p class="p3">In most primitives this is referred to by the variable 'a'.</p>
115 <p class="p9"><br></p>
116 <p class="p9"><br></p>
117 <p class="p2"><br></p>
118 <p class="p2"><br></p>
119 </body>
120 </html>